﻿
#region 文件信息
/*----------------------------------------------------------------
// 
// 文件名称：	
// 文件功能描述：	
// 设计要求：	
//
// 文 件 名：    AopProxyGenerator
// 创建者：      杨程
// 创建日期：	    2023/2/14 12:48:40

//----------------------------------------------------------------*/
#endregion

using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis;
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;

namespace Vampirewal.Core.SourceGeneratorMvvm.Generators;

public class AopProxySyntaxReceiver : ISyntaxReceiver
{
    public List<AttributeSyntax> CandidateClasses { get; } = new List<AttributeSyntax>();
    public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
    {
        if (syntaxNode is AttributeSyntax cds && cds.Name is IdentifierNameSyntax identifierName && identifierName.Identifier.ValueText == "GeneratorAopProxy")
        {
            CandidateClasses.Add(cds);
        }

        //if (syntaxNode is ClassDeclarationSyntax cds1 && cds1.BaseList != null && cds1.BaseList.Types.Where(w => ((IdentifierNameSyntax)w.Type).Identifier.ValueText == "AopBase").Count() > 0)
        //{

        //    var aaa = cds1.BaseList;

        //    var bbb = (aaa.Parent as ClassDeclarationSyntax);

        //    var ccc = aaa.Types;


        //    //ccc.FirstOrDefault(f => f.Typ)

        //    foreach (var item in ccc)
        //    {
        //        var aaaa = item.Type;

        //        var asd = (aaaa as IdentifierNameSyntax).Identifier.ValueText;

        //        var str = aaaa.GetText();
        //    }
        //}


    }
}

/// <summary>
/// 
/// </summary>
[Generator]
public partial class AopProxyGenerator : ISourceGenerator
{
    public void Execute(GeneratorExecutionContext context)
    {
        var syntaxReceiver = (AopProxySyntaxReceiver)context.SyntaxReceiver;
        var attributeSyntaxList = syntaxReceiver.CandidateClasses;

        if (attributeSyntaxList.Count == 0)
        {
            return;
        }

        List<string> ClassName = new List<string>();

        foreach (AttributeSyntax attributeSyntax in attributeSyntaxList)
        {
            // 找到class，并且判断一下是否有parital字段
            var classDeclarationSyntax = attributeSyntax.FirstAncestorOrSelf<ClassDeclarationSyntax>();
            if (classDeclarationSyntax == null || !classDeclarationSyntax.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword)))
            {
                continue;
            }

            //判断是否已经处理过这个class了
            if (ClassName.Contains(classDeclarationSyntax.Identifier.ValueText))
            {
                continue;
            }

            // 找到namespace
            var namespaceDeclarationSyntax = classDeclarationSyntax.FirstAncestorOrSelf<BaseNamespaceDeclarationSyntax>();
            

            // 找到methods
            var methodDeclarationList = classDeclarationSyntax.Members.OfType<MethodDeclarationSyntax>().ToList();
            if (methodDeclarationList.Count == 0)
            {
                continue;
            }

            StringBuilder sb = new StringBuilder();

            sb.AppendLine("using Vampirewal.Core.SimpleMVVM;");
            sb.AppendLine("using Vampirewal.Core.Attributes;");
            sb.AppendLine("using System.Reflection;");
            sb.AppendLine();

            sb.AppendLine($"namespace {namespaceDeclarationSyntax.Name}");
            sb.AppendLine("{");

            sb.AppendLine($"    public partial class {classDeclarationSyntax.Identifier.Text}");
            sb.AppendLine("    {");

            foreach (MethodDeclarationSyntax methodDeclaration in methodDeclarationList)
            {
                //判断一下是否包含AOP结尾的特性
                if (!SyntaxUtils.HasAopAttribute(methodDeclaration, out AttributeSyntax AopAttribute))
                {
                    continue;
                }

                var AopAttributeName = (AopAttribute.Name as IdentifierNameSyntax).Identifier.ValueText;

                //获取方法的返回值字符串
                var ReturnTypeStr = (methodDeclaration.ReturnType as PredefinedTypeSyntax).Keyword.ValueText;

                //获取方法内的参数
                var ParameterList = methodDeclaration.ParameterList.Parameters;

                //var asd= ParameterList.Select(s => $"{s.ToFullString().Split(' ')[1]}").ToList();

                sb.AppendLine("/// <summary>");
                sb.AppendLine($"/// {methodDeclaration.Identifier.Text}的AOP代理方法");
                sb.AppendLine($"/// <para>多个AOP特性均会执行</para>");
                sb.AppendLine("/// </summary>");
                sb.AppendLine($"public {ReturnTypeStr} {methodDeclaration.Identifier.Text}_Proxy ({string.Join(",", ParameterList.Select(s => $"{s.ToFullString()}"))})");
                sb.AppendLine("{");
                

                if (ReturnTypeStr != "void")
                {
                    sb.AppendLine($"return ({ReturnTypeStr})ExcuteProxy(\"{ methodDeclaration.Identifier.Text}\",{string.Join(",", ParameterList.Select(s => $"{s.ToFullString().Split(' ')[1]}"))});");
                }
                else
                {
                    sb.AppendLine($"ExcuteProxy(\"{methodDeclaration.Identifier.Text}\",{string.Join(",", ParameterList.Select(s => $"{s.ToFullString().Split(' ')[1]}"))});");
                }


                sb.AppendLine("}");
            }

            sb.AppendLine("/// <summary>");
            sb.AppendLine("/// 执行代理方法");
            sb.AppendLine("/// </summary>");
            sb.AppendLine($@"


private object ExcuteProxy(string MethodName,params object[] args)
    {{
        object result = null;

        var method = this.GetType().GetMethod(MethodName);
        object[]? attrs = method.GetCustomAttributes(true);

        foreach (var item in attrs)
        {{
            if (item is AopBaseAttribute aop)
            {{
                AopMethod aopMethod = new AopMethod(this, method, args);
                Exception ex = null;
                try
                {{
                    if (aop.Location == InvokeLocation.Before)
                    {{
                        aop.ExcuteBefore();
                    }}

                    if (aop.Location == InvokeLocation.Both)
                    {{
                        aop.ExcuteMiddle(aopMethod);
                    }}
                }}
                catch (Exception exx)
                {{
                    ex=exx;
                }}

                if (aopMethod.ReturnValue is Task)
                {{
                    (aopMethod.ReturnValue as Task).ContinueWith((Task t) =>
                    {{
                        aop.ExcuteAfter(aopMethod, t.Exception);
                    }});
                }}
                else
                {{
                    aop.ExcuteAfter(aopMethod, ex);
                }}

                result = aopMethod.ReturnValue;
            }}
        }}

        return result;
    }}
");

            sb.AppendLine("    }");
            sb.AppendLine("}");

            string extensionTextFormatted = CSharpSyntaxTree.ParseText(sb.ToString(), new CSharpParseOptions(LanguageVersion.CSharp8)).GetRoot().NormalizeWhitespace().SyntaxTree.GetText().ToString();
            // 添加到源代码，这样IDE才能感知
            context.AddSource($"{classDeclarationSyntax.Identifier}.g.cs", SourceText.From(extensionTextFormatted, Encoding.UTF8));
            // 保存一下类名，避免重复生成
            ClassName.Add(classDeclarationSyntax.Identifier.ValueText);
        }
    }

    public void Initialize(GeneratorInitializationContext context)
    {
#if DEBUG
        //Debugger.Launch();
#endif

        context.RegisterForSyntaxNotifications(() => new AopProxySyntaxReceiver());
    }
}
